package com.codeape.number.base.mvvm.command;

import androidx.annotation.NonNull;

import java.util.concurrent.Callable;

/**
 * ResponseCommand
 *
 * @author LiuPeiming
 * Created at 2018/11/1 4:13
 */
public class ResponseCommand<T, R> {

    private Callable<R> execute0;
    private Function<T, R> execute1;

    private Callable<Boolean> canExecute0;

    /**
     * like {@link Command},but ResponseCommand can return result when command has executed!
     *
     * @param execute function to execute when event occur.
     */
    public ResponseCommand(Callable<R> execute) {
        this.execute0 = execute;
    }


    public ResponseCommand(Function<T, R> execute) {
        this.execute1 = execute;
    }


    public ResponseCommand(Callable<R> execute, Callable<Boolean> canExecute0) {
        this.execute0 = execute;
        this.canExecute0 = canExecute0;
    }


    public ResponseCommand(Function<T, R> execute, Callable<Boolean> canExecute0) {
        this.execute1 = execute;
        this.canExecute0 = canExecute0;
    }


    public R execute() {
        if (execute0 != null && canExecute0()) {
            try {
                return execute0.call();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private boolean canExecute0() {
        if (canExecute0 == null) {
            return true;
        }
        try {
            return canExecute0.call();
        } catch (Exception e) {
            e.printStackTrace();
            return true;
        }
    }


    public R execute(T parameter) {
        if (execute1 != null && canExecute0()) {
            try {
                return execute1.apply(parameter);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * A functional interface that takes a value and returns another value, possibly with a
     * different type and allows throwing a checked exception.
     *
     * @param <T> the input value type
     * @param <R> the output value type
     */
    interface Function<T, R> {
        /**
         * Apply some calculation to the input value and return some other value.
         *
         * @param t the input value
         * @return the output value
         * @throws Exception on error
         */
        @NonNull
        R apply(@NonNull T t) throws Exception;
    }
}
